#!/bin/bash
# 实现, 对于一个内核模块工程的创建; 也就是说是一个create命令; 
# 基本使用方法; 
# help 		打印当前文档中所有的帮助信息; 

#定义常见的参数; 
HELP=""
DIR="."   #默认是在当前目录创建,也可以制定创建目录; 
PRO_NAME=""
MAKEFILE=""
KERNEL_DIR=""
COMPLETE_PRO_NAME=""

#定义错误返回码; 
EXIT_HELP=0
EXIT_NODIR=1
EXIT_DIREXIST=2
EXIT_PARAM=3
EXIT_CREATEDIRERROR=4

EXIT_KERNEL_DIR_NONEXIST=10

help()
{
	echo "===== create help start ====="
	echo "create:"
	echo "       [-n/--name project_name] 输入工程名字 （必选）"
	echo "       <-m/--Makefile> 选择不创建makefile文件 （可选）"
	echo "       <-d/--directory pos> 选择目录的位置，默认为当前目录(可选)"
	echo "       <-h/--help> 帮助信息"
	echo "===== create help end   ====="

}
parse_param()
{
	param_num=$(echo ""$#"+1"|bc)
	for((i=1;i<"$param_num";i++))
	do
		case "$1" in 
			"-h"|"--help")
				HELP="-h"
				;;
			"-d"|"--dirctory")
				i=$(echo ""$i"+1"|bc)
				shift
				DIR="$1"
				if [ ! -d "$DIR" ]
				then
					echo "您输入的目录错误;"
					exit "$EXIT_NODIR"
				fi
				;;
			"-n"|"--name")
				i=$(echo ""$i"+1"|bc)
				shift
				PRO_NAME="$1"
				;;
			"-m"|"--Makefile")
				MAKEFILE="no makefile"
				;;
			*)
				echo "输入参数有误: "$1
				exit "$EXIT_PARAM"
				;; 
		esac
		shift
	done
}
create_init_file()
{
	FILENAME="$COMPLETE_PRO_NAME""/""$PRO_NAME"".c"
	echo '#include<linux/init.h>' >> "$FILENAME"
	echo '#include<linux/module.h>' >> "$FILENAME"
	echo '#include<linux/kernel.h>' >> "$FILENAME"
	echo ' ' >> "$FILENAME" 
	echo "static int __init "$PRO_NAME"_init (void)" >> "$FILENAME"
	echo '{' >> "$FILENAME"
	echo -e "\t"'printk("''hello kernel\\n''");' >> "$FILENAME" 
	echo -e "\t"'return 0;' >> "$FILENAME"
	echo '}' >> "$FILENAME"
	echo ' ' >> "$FILENAME"
	echo 'static void __exit '"$PRO_NAME"'_exit (void)' >> "$FILENAME"
	echo '{' >> "$FILENAME"
	echo -e "\t"'printk("''goodbye kernel\\n''");' >> "$FILENAME" 
	echo '}' >> "$FILENAME"
	echo ' ' >> "$FILENAME"
	echo 'module_init('"$PRO_NAME"'_init);' >> "$FILENAME"
	echo 'module_exit('"$PRO_NAME"'_exit);' >> "$FILENAME"
	echo 'MODULE_LICENSE("GPL");' >> "$FILENAME"
}


#自动扫描kernel的位置; 
scan_kernel_pos()
{
	KERNEL_VERSION=`uname -r`; 
	KERNEL_DIR=`ls -l /lib/modules | grep "$KERNEL_VERSION"`
	if [ "$KERNEL_DIR" == "" ] 
	then 
		return EXIT_KERNEL_DIR_NONEXIST
	fi
	#kernel的位置存在; 
	KERNEL_DIR=`ls -l /lib/modules/"$KERNEL_VERSION" | cut -d '>' -f 2 | head -2 | tail -1`
}

parse_param $*

#help信息; 
if [ "$HELP" != "" ] 
then
	help
	exit  "$EXIT_HELP"
fi

#创建工程文件; 
if [ "$PRO_NAME" == "" ] 
then
	echo "请您输入正确的工程名字"
	exit $EXIT_NODIR
else
	echo "正在创建工程文件"
	if [ "$DIR" == "." ] 
	then
		DIR=`pwd`
	fi
	COMPLETE_PRO_NAME="$DIR""/""$PRO_NAME"
	if [ -e "$COMPLETE_PRO_NAME" ] 
	then
		echo "您输入的工程名在文件夹中已经存在,无法创建,请您更换其他的文件名"
		exit "$EXIT_DIREXIST" 
	fi
	echo "开始创建工程目录:""$COMPLETE_PRO_NAME"
	if ! mkdir "$COMPLETE_PRO_NAME" > /dev/null 2>&1
	then 
		echo "创建工程目录失败，请重新尝试"
		exit "$EXIT_CREATEDIRERROR"
	fi
	echo "创建工程目录:"$COMPLETE_PRO_NAME"成功"

	#开始创建模块参数; 
	echo "开始创建初始化文件:"$PRO_NAME".c"
	create_init_file;
	echo "初始化文件:"$PRO_NAME".c创建成功"
fi

#创建Makefile文件; 
if [ "$MAKEFILE" != "" ] 
then
	echo "您已经选择不创建Makefile文件;"
else
	scan_kernel_pos
	if [ "$KERNEL_DIR" == "" ] 
	then
		echo "您的kernel位置自动扫描失败,请手动输入您的kernel位置;"
		read -p "请输入: " KERNEL_DIR
		if [ ! -d "$KERNEL_DIR" ] 
		then 
			echo "您输入的目录不存在"
			exit EXIT_KERNEL_DIR_NONEXIST; 
		fi
	fi
	cd "$COMPLETE_PRO_NAME" > /dev/null
	echo "开始创建Makefile文件;" 
  echo "obj-m := $PRO_NAME.o" >> Makefile
	echo "CURRENT_PATH := "'$(shell pwd)' >> Makefile
	echo 'LINUX_KERNEL := $(shell uname -r)' >> Makefile
	echo "LINUX_KERNEL_PATH := $KERNEL_DIR" >> Makefile
 	echo 'all:' >> Makefile
	echo -e "\t"'make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules' >> Makefile
 	echo 'clean:' >> Makefile
	echo -e "\t"'make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean' >> Makefile
	echo "创建Makefile文件成功"
	cd - > /dev/null
fi
echo "项目创建成功，Happy Coding"
